//***********************************************************************
//	File:		Game.h
//	Author:		Doug Monroe
//	Course:		SGD 1404
//	Purpose:	Game class runs the game logic
//***********************************************************************

#pragma once

#include "../SGD Wrappers/SGD_Handle.h"
#include "../SGD Wrappers/SGD_Declarations.h"
#include "../SGD Wrappers/SGD_Geometry.h"
#include "../SGD Wrappers/SGD_GraphicsManager.h"

#include "../SGD Wrappers/SGD_InputManager.h"

#include <string>
#include "Emitter.h"

class BitmapFont;
class IGameState;

//***********************************************************************
// Forward class declaration
//	- tells the compiler that the typename exists
//	- only allows creating POINTERS & REFERENCES of the type
//	- the full #include is in the .cpp file
class GameObject;
class ObjectManager;


#define NUM_SONGS 6
#define NUM_SFX 15

//***********************************************************************
// Game class
//	- handles the SGD wrappers
//	- runs the game logic
//	- SINGLETON
//		- only ONE instance can be created
//		- global access to THE instance
class Game
{
public:
	//*******************************************************************
	// SINGLETON!
	//	- static accessor to get the singleton object
	static Game* GetInstance	( void );
	static void  DeleteInstance	( void );

	
	//*******************************************************************
	// Setup, Play, Cleanup
	bool	Initialize	( float width, float height );
	int		Update		( void );
	void	Terminate	( void );

	// cursor image
	SGD::HTexture GetCursorImage() const { return cursorImage; }
	
	//*******************************************************************
	// Screen Size Accessors:
	float	GetScreenWidth	( void ) const	{	return m_fScreenWidth;	}
	float	GetScreenHeight ( void ) const	{	return m_fScreenHeight;	} 

	//enumeration for song array
	enum Songs{  HUB, FOREST, CAVE, CASTLE, VOLCANO, MENU};
	SGD::HAudio GetSong(int index) { return music[index]; }

	//enumeration for the soundEffects array
	enum SFX{ARCANESHOT, BEAM, EXPLOSIVE, FIREBLAST, COMBOBREAKER, ELECTRON, PHOTON, SHOCKWAVE, PORTAL,
	VAMPIRIC, DOUBLE, SOLARFLARE, SEEKER, MAGICMISSILE, SMALLCOMBOBREAK};
	void PlaySFX(int sfx);

	SGD::HTexture GetMenuBackground() { return menuBackground; }

	//Camera Accessor + Mutator
	SGD::Point		GetCameraPos(void) const { return m_pCameraPos; }
	void			SetCameraPos(SGD::Point campos, SGD::Rectangle getrect);
	// Font Accessor:
	BitmapFont* GetFont(void) const	{ return m_pFont; }

	//Sound effects and Music Volume Controls Accessors and Mutators
	int GetSoundVol(void) const { return m_SoundFXVol; }
	int GetMusicVol(void) const { return m_MusicVol; }
	SGD::HAudio& GetMenuConfirm() { return menuSelectionConfirm; }

	void SetSoundVol(int vol) { m_SoundFXVol = vol; }
	void SetMusicVol(int vol) { m_MusicVol = vol; }

	bool GetWindowd(void) const { return m_bWindowd; }
	void SetWindowd(bool wind) { m_bWindowd = wind; }

	void LoadAudioFile();
	void SaveAudioFile();

	std::string& GetLevel(int level) { return levelNames[level]; }
	std::string& GetName(int level, int index) { return names[level][index]; }
	SGD::HAudio& GetEnemyDamaged() { return enemyDamaged; }
	int GetScore(int level, int index) { return scores[level][index]; }
	int GetCombo(int level, int index) { return combos[level][index]; }

		void SetName(int level, int index, std::string name) { names[level][index] = name; }
	void SetScore(int level, int index, int score) { scores[level][index] = score; }
	void SetCombo(int level, int index, int Combo) { combos[level][index] = Combo; }

	SGD::HTexture& GetHTPImage() { return m_hInstructions; }
	SGD::HTexture& GetControllerImage() { return m_hControllerimage; }

	void LoadHighScores(void);
	/**********************************************************/
	// Game State Machine:
	//	- can ONLY be called by the state's Input, Update, or Render methods!!!
	void ChangeState(IGameState* pNewState);

#pragma region input functions
	bool FireInput();
	bool JumpInput();
	bool MovementAbilityInput();
	bool LeftInput(SGD::Vector tempvec);
	bool RightInput(SGD::Vector tempvec);
	bool UpInput(SGD::Vector tempvec);
	bool UpInputPressed(SGD::Vector tempvec);
	
	bool DownInput(SGD::Vector tempvec);
	bool HoldPositionInput();

	bool HotSwapUpInput();
	bool HotSwapRightInput();
	bool HotSwapDownInput();
	bool HotSwapLeftInput();

	bool upPressed = false;
	bool rightPressed = false;
	bool downPressed = false;
	bool leftPressed = false;

	bool RStickupPressed = false;
	bool RStickrightPressed = false;
	bool RStickdownPressed = false;
	bool RStickleftPressed = false;

	bool MenuUpInput();
	bool MenuDownInput();
	bool MenuRightInput();
	bool MenuLeftInput();

	bool MenuConfirmInput();
	bool MenuBackInput();
	bool MenuDeleteInput();

	bool PauseInput();

	bool TableCycleLeftInput();
	bool TableCycleRightInput();
	bool ExitTableInput();
#pragma endregion

private:
	//*******************************************************************
	// SINGLETON!
	//	- static member to hold the singleton object
	//	- prevent access to constructors / destructor / =op
	static Game* s_pInstance;

	Game( void )					= default;	// default constructor
	~Game( void )					= default;	// destructor

	Game( const Game& )				= delete;	// disable copy constructor
	Game& operator= ( const Game& )	= delete;	// disable assignment operator

	//*******************************************************************
	// Screen Size
	float			m_fScreenWidth		= 0;
	float			m_fScreenHeight = 0;
	bool			bossArea = false;

	//Camera
	SGD::Point		m_pCameraPos = SGD::Point{ 0, 0 };
	
	//Sound Effects and Music Volume Control
	int m_SoundFXVol = 100;
	int m_MusicVol = 100;
	bool m_bWindowd = true;
	/**********************************************************/
	// Current Game State
	IGameState*				m_pCurrState = nullptr;


	/**********************************************************/
	// Game Font
	BitmapFont*				m_pFont = nullptr;



	//*******************************************************************
	// Game Time
	unsigned long	m_ulGameTime		= 0;
	float elapsedTime;
	//*******************************************************************
	// FPS
	unsigned int	m_unFPS				= 60;
	unsigned int	m_unFrames			= 0;
	float			m_fFPSTimer			= 0.0f;

	std::string	levelNames[4];
	std::string	names[4][10];
	int			scores[4][10];
	int			combos[4][10];

	SGD::InputManager* pInput = SGD::InputManager::GetInstance();
	SGD::GraphicsManager* pGraphics = SGD::GraphicsManager::GetInstance();

	SGD::HAudio music[NUM_SONGS];
	int numSongs = NUM_SONGS;

	SGD::HAudio menuSelectionChange = SGD::INVALID_HANDLE;
	SGD::HAudio menuSelectionConfirm = SGD::INVALID_HANDLE;
	SGD::HAudio enemyDamaged = SGD::INVALID_HANDLE;
	SGD::HAudio soundEffects[NUM_SFX];

	SGD::HTexture menuBackground = SGD::INVALID_HANDLE;
	SGD::HTexture forestBackground = SGD::INVALID_HANDLE;
	SGD::HTexture cursorImage = SGD::INVALID_HANDLE;

	SGD::HTexture m_hControllerimage = SGD::INVALID_HANDLE;
	SGD::HTexture m_hInstructions = SGD::INVALID_HANDLE;

};
